﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Pex.Engine.ComponentModel;
using Microsoft.Pex.Engine.Explorable;
using Microsoft.ExtendedReflection.Metadata;
using Microsoft.ExtendedReflection.Interpretation;
using Microsoft.ExtendedReflection.Collections;
using Microsoft.ExtendedReflection.Logging;
using Microsoft.ExtendedReflection.Utilities.Safe.Diagnostics;
using Microsoft.ExtendedReflection.Utilities.Safe;
using Microsoft.ExtendedReflection.Feedback;

namespace HintProvider
{
    internal class PexMeFactoryGuesser
        : PexComponentElementBase, IPexExplorableGuesser
    {
        IPexComponent host;        

        public PexMeFactoryGuesser(IPexComponent host)
            : base(host)
        {
            this.host = host;
        }
                
        /// <summary>        
        /// </summary>
        /// <param name="explorableType"></param>
        /// <returns></returns>
        public IEnumerable<PexExplorableCandidate> GuessExplorables(TypeEx explorableType)
        {
            SafeDebug.AssumeNotNull(explorableType, "explorableType");
            this.host.Log.LogMessage("Exprolables", "Requested for type: " + explorableType);                      
            
            //the following factory is not returned to be used in sequence explroation but used to check
            //whether things are valid
            PexExplorableFactory localExplorableFactory;
            bool result = PexExplorableFactory.TryGetExplorableFactory(this.host, explorableType, out localExplorableFactory);

            if (explorableType.DefaultConstructor != null)
            {
                Method bestConstructorMethod = null;
                bestConstructorMethod = explorableType.DefaultConstructor;

                #region default factory method from the original Pex: scan visible methods, order by call depth, add methods as setters

                //start building the method sequence            
                PexExplorableFactory originalExplorableFactory;
                result = PexExplorableFactory.TryGetExplorableFactory(this.Host, explorableType, out originalExplorableFactory);

                //add constructor
                if (!originalExplorableFactory.TrySetFactoryMethod(bestConstructorMethod))
                {
                    SafeDebug.Fail("we checked before that it is valid");
                    yield break;
                }

                IPexExplorable originalExplorable1 = originalExplorableFactory.CreateExplorable();
                CodeUpdate.AddMethodCodeUpdate originalPreviewUpdate1;
                CodeUpdate originalUpdate1 = originalExplorableFactory.CreateExplorableFactoryUpdate(out originalPreviewUpdate1);

                //return the original one after own suggested            
                yield return new PexExplorableCandidate(originalExplorable1, false, originalUpdate1);
            }
            #endregion
            yield break;
        }
    }
}
